package org.digitarts.rtms.tracing;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

import org.digitarts.rtms.helpers.StringHelper;
import org.digitarts.rtms.spring.collectors.cache.ICacheStore;
import org.digitarts.rtms.spring.collectors.cache.SampleCount;
import org.digitarts.rtms.tracing.threads.ThreadInfoCapture;


public class CachingTracer implements ITracer
{
	protected ITracer			innerTracer				= null;
	protected Set<ICacheStore>	caches					= new HashSet<ICacheStore>();
	protected Set<Pattern>		metricFilterPatterns	= null;
	protected SampleCount		sampleCount				= new SampleCount();

	public CachingTracer(ITracer innerTracer, Set<Pattern> metricFilterPatterns, SampleCount sampleCount, Set<ICacheStore> caches)
	{
		super();
		this.innerTracer = innerTracer;
		this.metricFilterPatterns = metricFilterPatterns;
		this.sampleCount = sampleCount;
		this.caches = caches;
	}

	protected boolean shouldCache(String[] nameSpace, String type)
	{
		if (caches == null || caches.size() < 1)
			return false;
		String traceName = Trace.traceName(nameSpace, type);
		if (metricFilterPatterns != null && metricFilterPatterns.size() > 0)
		{
			if (!StringHelper.anyMatches(traceName, metricFilterPatterns))
			{
				return false;
			}
		}
		return sampleCount.cache();
	}

	public ThreadInfoCapture endThreadInfoCapture(String... name)
	{
		return innerTracer.endThreadInfoCapture(name);
	}

	public String lookupRange(String rangeName, long value)
	{
		return innerTracer.lookupRange(rangeName, value);
	}

	public long sizeOf(Object obj)
	{
		return innerTracer.sizeOf(obj);
	}

	public void startThreadInfoCapture(int options, boolean nanoTime)
	{
		innerTracer.startThreadInfoCapture(options, nanoTime);
	}

	public void startThreadInfoCapture(int options)
	{
		innerTracer.startThreadInfoCapture(options);
	}

	public void trace(Date value, String... name)
	{
		innerTracer.trace(value, name);
	}

	public void trace(int value, String... name)
	{
		innerTracer.trace(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_INT))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_INT, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}
	}

	public void trace(long value, String... name)
	{
		innerTracer.trace(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_LONG))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_LONG, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void trace(String value, String type, String... name)
	{
		innerTracer.trace(value, type, name);
		if (shouldCache(name, type))
		{
			Trace trace = new Trace(name, type, value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void trace(String value, String... name)
	{
		innerTracer.trace(value, name);
	}

	public void traceDelta(int value, String... name)
	{
		innerTracer.traceDelta(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_DELTA_INT))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_DELTA_INT, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void traceDelta(long value, String... name)
	{
		innerTracer.traceDelta(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_DELTA_LONG))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_DELTA_LONG, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void traceDeltaSticky(int value, String... name)
	{
		innerTracer.traceDeltaSticky(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_DELTA_STICKY_INT))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_DELTA_STICKY_INT, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}
	}

	public void traceDeltaSticky(long value, String... name)
	{
		innerTracer.traceDeltaSticky(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_DELTA_STICKY_LONG))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_DELTA_STICKY_LONG, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void traceIncident(int value, String... name)
	{
		innerTracer.traceIncident(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_INCIDENT))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_INCIDENT, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}
	}

	public void traceIncident(String... name)
	{
		innerTracer.traceIncident(name);
		if (shouldCache(name, ITracer.METRIC_TYPE_INCIDENT))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_INCIDENT, "1");
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void traceSticky(int value, String... name)
	{
		innerTracer.traceSticky(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_COUNTER_INT))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_COUNTER_INT, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}

	public void traceSticky(long value, String... name)
	{
		innerTracer.traceSticky(value, name);
		if (shouldCache(name, ITracer.METRIC_TYPE_COUNTER_LONG))
		{
			Trace trace = new Trace(name, ITracer.METRIC_TYPE_COUNTER_LONG, "" + value);
			for (ICacheStore cache : caches)
			{
				cache.addCacheItem(trace);
			}
		}

	}
}
